package com.project.controller;

import com.project.bean.ImgEntity;
import com.project.bean.NewsEntity;
import com.project.dao.IMeituanDao;
import com.project.dao.INewsDao;
import com.project.dto.CinemaDto;
import com.project.dto.OrderDto;
import com.project.service.CinemaRemoteService;
import com.project.util.CacheUtil;
import com.project.util.RedisCacheUtil;
import com.project.util.StringUtil;
import com.rabbitmq.client.Channel;
import org.redisson.api.RLock;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @Author(王思翰)
 * @Description(类的描述)
 * @Date(创建时间) 2021/9/7 16:57
 */
@RestController
@RequestMapping("meituan")
public class MeituanController {
    @Autowired
    CinemaRemoteService cinemaRemoteService;
    //    @Autowired
//    RabbitTemplate rabbitTemplate;
    @Autowired
    IMeituanDao meituanDao;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RedisCacheUtil redisCacheUtil;

    @Autowired
    RLock rLock;

    @Autowired
    INewsDao iNewsDao;

    /**
     * 回调方法
     */
    RabbitTemplate.ConfirmCallback callback = (CorrelationData correlationData, boolean b, String s) -> {
        //投递成功
        if (b) {
            //获得关联数据,movieId
            String orderIdStr = correlationData.getId();
            int orderId = Integer.parseInt(orderIdStr);
            //把订单状态改为1
//            OrderEntity orderEntity = orderDao.findById(orderId).get();
//            orderEntity.setTag(1);
//            orderDao.save(orderEntity);

            System.out.println("发送信息确认" + meituanDao.findById(orderId));

        }
    };

    @PostMapping("ImgPost")
    public ImgEntity ImgPost(@RequestParam("file") MultipartFile file) {
        String fileName = file.getOriginalFilename();
        if (fileName.substring(fileName.lastIndexOf(".")).equals(".jpg") && fileName.length() > 0) {
            fileName = System.currentTimeMillis() +
                    fileName.substring(fileName.lastIndexOf("."));
            File newFile = new File(StringUtil.FILE_PATH + fileName);
            try {
                file.transferTo(newFile);
                ImgEntity imgEntity=new ImgEntity();
                imgEntity.setLocation(fileName);
                System.out.println(imgEntity);
                return imgEntity;
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    @PostMapping("esTest")
    public String esTest(@RequestParam("title")String title,
                         @RequestParam("info")String info,
                         @RequestParam("type")String type,
                         @RequestParam("time")String time){
        NewsEntity entity=new NewsEntity();
        entity.setTitle(title);
        entity.setInfo(info);
        entity.setType(type);
        entity.setTime(time);
        iNewsDao.save(entity);
        return "添加成功";

    }
    @GetMapping("esTestOne")
    public List<NewsEntity> esTestOne(){
        return iNewsDao.findAll();
    }

    @GetMapping("esTestTwo/{info}")
    public List<NewsEntity> esTestTwo(@PathVariable("info") String info){
        return iNewsDao.findAllByInfo(info);
    }

    @GetMapping("esTestThere/{type}")
    public List<NewsEntity> esTestThere(@PathVariable("type") String type){
        return iNewsDao.findAllByType(type);
    }

    @GetMapping("findByAll")
    public List<CinemaDto> findByAll() {
        List<CinemaDto> list = cinemaRemoteService.findByAll();
        for (CinemaDto cinema : list) {
            CinemaDto cinemaDto = meituanDao.findByNane(cinema.getName());
            if (cinemaDto == null) {
                meituanDao.addCinema(cinema);
            }
        }
        return list;
    }

    @GetMapping("addOrder/{id}/{name}/{money}")
    public String addOrder(@PathVariable("id") int id
            , @PathVariable("name") String name
            , @PathVariable("money") int money) {
        OrderDto orderDto = new OrderDto();
        orderDto.setCid(id);
        orderDto.setCname(name);
        orderDto.setCmoney(money);
        meituanDao.addOrder(orderDto);
        cinemaRemoteService.addOrder(id, name, money);
        redisTemplate.opsForSet().add("order", orderDto);
        redisCacheUtil.expire("order", 30);
        return "添加订单成功";
    }


    @GetMapping("findByOrderAll")
    public List<OrderDto> findByOrderAll() {
        System.out.println(redisCacheUtil.getExpire("order"));
        return meituanDao.findByAll();
    }

    /**
     * 压力测试
     *
     * @param name
     * @param tag
     * @return
     */
    @GetMapping("orderInfo/{movieName}/{tag}")
    public List<Map> orderInfo(@PathVariable("movieName") String name,
                               @PathVariable("tag") int tag) throws InterruptedException {
        //布隆缓存穿透过滤
        String tagStr = String.valueOf(tag);
        if (!CacheUtil.bloomFilter.mightContain(name) || !CacheUtil.bloomFilter.mightContain(tagStr)) {
            return null;
        }

        List<Map> list = null;
        if (redisCacheUtil.hasKey("order")) {
            //查询缓存
            Set set = redisCacheUtil.sGet("order");
            System.out.println(set);

        } else {
            //去竞争锁
            //尝试加锁，最多等待0秒，上锁以后100秒自动解锁
            boolean res = rLock.tryLock(0, 100, TimeUnit.SECONDS);
            System.out.println(res);
            if (res) {
                //如果缓存没有就查询数据库
                OrderDto orderDto = meituanDao.findById(tag);
                if (orderDto == null) {
                    //如果查询结果为空
                    redisCacheUtil.sSet("order", orderDto, CacheUtil.CacheTimeMin);
                } else {
                    //把数据放入缓存
                    int time = (int) (Math.random() * (CacheUtil.CacheTimeMax - CacheUtil.CacheTimeMin) + CacheUtil.CacheTimeMin);
                    //解决缓存雪崩，防止同时间失效
                    redisCacheUtil.sSet("order", meituanDao.findById(tag), time);
                }
                rLock.unlock();
            } else {
                //如果没有拿到锁，就等待一会然后重新访问该方法
                Thread.sleep(500);
                this.orderInfo(name, tag);
            }
        }

        return list;
    }


    @GetMapping("findByRadisOrderAll")
    public Set<OrderDto> findByRadisOrderAll() {
        return redisTemplate.opsForSet().members("order");
    }

    @GetMapping("chupiao/{id}")
    public String chupiao(@PathVariable("id") int id) throws InterruptedException {

//        //开启手动确认
//        rabbitTemplate.setMandatory(true);//开启消息确认
//        //绑定回调函数
//        rabbitTemplate.setConfirmCallback(callback);

        OrderDto orderDto = meituanDao.findById(id);
        System.out.println("出票：" + orderDto);
        if (orderDto.getStatus().equals("未出票")) {
            meituanDao.update(id);
            meituanDao.updateDianyingyuan(id);
//            redisTemplate.opsForValue().set("orderDto",orderDto);
            redisTemplate.opsForSet().add("orderDto", orderDto);
            if (redisCacheUtil.expire("orderDto", 60)) {
                return "修改成功";
            }
//            //组装关联数据
//            CorrelationData correlationData = new CorrelationData(String.valueOf(orderDto.getId()));
//            System.out.println("在出票中开启手动确认和绑定回调");
//            rabbitTemplate.convertAndSend("meituanDirect", "meituan.Direct", orderDto, correlationData);
//            Thread.sleep(500);
        }
        return "该订单以出票";
    }

    //    @RabbitListener(queues = "meituanQueue")
    public void updateNumber() {
//        System.out.println("手动确认中打印"+orderDto);


//        int i=1/0;//模拟在处理业务是出现异常

        //确认收到，如果没有此行代码，那么就算收到了信息，也会标记为等待验证状态
//        channel.basicAck(tag,false);
    }
}
